﻿using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Collections.Generic;

// 2008 by Mario Meir-Huber
// Mail: mario_mh@vb-magazin.de
//       i-mameir@microsoft.com
namespace ChartLibrary.Data
{
    /// <summary>
    /// This class is a one dimensional data source object used for the classes
    /// </summary>
    /// <history>
    ///     03/15/08: Design and Implementation for 0.1
    ///     03/18/08: Implemented Enumerator
    /// </history>
    public class DataSource : IEnumerator<ChartData>
    {
        private List<ChartData> _lst = null;    //List to store objects
        private string _name = string.Empty;    //Name of the data source
        private IDataChanged _parent = null;       //Parent to this class
        private double _min = 0.0;              //Minimal value
        private double _max = 0.0;              //Maximal value
        private object _tag = null;             //Tag for custom Data
        private int enumposition = -1;          //index position for enumerator           

        /// <summary>
        /// This initializes the class
        /// </summary>
        private DataSource()
        {
            _lst = new List<ChartData>();
            Fill = new SolidColorBrush(Color.FromArgb(255, 0, 0, 0));
        }

        /// <summary>
        /// This initializes the class
        /// </summary>
        /// <param name="parent">Parent of the class</param>
        public DataSource(IDataChanged parent) : this()
        {
            _parent = parent;
        }

        /// <summary>
        /// This initializes the class
        /// </summary>
        /// <param name="parent">Parent of this class</param>
        /// <param name="name">Name for the Data Object</param>
        public DataSource(IDataChanged parent, string name)
            : this(parent)
        {
            _name = name;
        }

        /// <summary>
        /// Adds a new value to the DataSource and notifys parent
        /// </summary>
        /// <param name="value">Value as a double</param>
        public void Add(double value)
        {
            ChartData tmp = new ChartData(value);
            Add(tmp);
            _parent.NotifyDataChanged(this);
        }

        /// <summary>
        /// Adds a new value to the Datasource  and notifys parent
        /// </summary>
        /// <param name="value">Value as a ChartData Object</param>
        public void Add(ChartData value)
        {
            AddIntern(value);
            _parent.NotifyDataChanged(this);
        }

        /// <summary>
        /// Adds a new value to the DataSource but doesn't notify parent
        /// </summary>
        /// <param name="value">Value as a double</param>
        private void AddIntern(double value)
        {
            ChartData tmp = new ChartData(value);
            AddIntern(tmp);
        }

        /// <summary>
        /// Adds a new value to the Datasource but doesn't notify parent
        /// </summary>
        /// <param name="value">Value as a ChartData Object</param>
        private void AddIntern(ChartData value)
        {
            if (_lst.Count == 0)
            {
                _max = value.Value;
                _min = value.Value;
            }
            else
            {
                if (value.Value > _max) _max = value.Value;
                if (value.Value < _min) _min = value.Value;
            }

            this._lst.Add(value);
        }

        /// <summary>
        /// Adds an Array to the Data Source
        /// </summary>
        /// <param name="value">Array of doubles</param>
        public void AddRange(double[] value)
        {
            foreach (double d in value)
            {
                AddIntern(d);
            }

            _parent.NotifyDataChanged(this);
        }

        /// <summary>
        /// Adds an Array to the Data Source
        /// </summary>
        /// <param name="value">Array of ChartData</param>
        public void AddRange(ChartData[] value)
        {
            foreach (ChartData c in value)
            {
                AddIntern(c);
            }

            _parent.NotifyDataChanged(this);
        }

        /// <summary>
        /// Clears the Data Source
        /// </summary>
        public void Clear()
        {
            _lst.Clear();

            _min = 0.0;
            _max = 0.0;

            _parent.NotifyDataChanged(this);
        }

        /// <summary>
        /// This gets the name of the Datasource or sets it
        /// </summary>
        public String Name 
        {
            get { return _name; }
            set { _name = value; }
        }

        /// <summary>
        /// This gets the amount of Items in the List
        /// </summary>
        public int Length
        { 
            get { return _lst.Count; }
        }

        /// <summary>
        /// This removes a ChartData Item from the List
        /// </summary>
        /// <param name="item">Item to Remove</param>
        public void Remove(ChartData item)
        {
            _lst.Remove(item);

            UpdateMinMax();

            _parent.NotifyDataChanged(this);
        }

        /// <summary>
        /// This removes a ChartData Item at the specified List
        /// </summary>
        /// <param name="index"></param>
        public void RemoveAt(int index)
        {
            _lst.RemoveAt(index);

            UpdateMinMax();

            _parent.NotifyDataChanged(this);
        }

        /// <summary>
        /// This gets the lowest Value
        /// </summary>
        public double Min
        { 
            get { return _min; }
        }

        /// <summary>
        /// This gets the highest Value
        /// </summary>
        public double Max
        {
            get { return _max; }
        }

        /// <summary>
        /// This finds the highest and lowest value
        /// </summary>
        private void UpdateMinMax()
        {
            if (_lst.Count > 0)
            {
                _max = _lst[0].Value;
                _min = _lst[0].Value;

                for (int i = 1; i < _lst.Count; i++)
                {
                    if (_lst[i].Value > _max) _max = _lst[i].Value;
                    if (_lst[i].Value < _min) _min = _lst[i].Value;
                }
            }
            else
            {
                _max = 0.0;
                _min = 0.0;
            }
        }

        /// <summary>
        /// This gets a custom storage or sets it
        /// </summary>
        public object Tag 
        {
            get { return _tag; }
            set { _tag = value; }
        }

        /// <summary>
        /// This sets ghe Fill for the DataSource
        /// </summary>
        public Brush Fill
        {
            get;
            set;
        }

        /// <summary>
        /// Gets the Chartdata at the specified position or sets it
        /// </summary>
        /// <param name="i">Index</param>
        /// <returns></returns>
        public ChartData this[int i]
        {
            get
            {
                if (i >= _lst.Count) throw new IndexOutOfRangeException("The index is out of the bounds of the array");

                return _lst[i];
            }
            set
            {
                if (i >= _lst.Count) throw new IndexOutOfRangeException("The index is out of the bounds of the array");

                _lst[i] = value;
            }
        }

        #region IEnumerator<ChartData> Members

        public ChartData Current
        {
            get { return _lst[enumposition]; }
        }

        #endregion

        #region IDisposable Members

        public void Dispose()
        {
            enumposition = -1;
        }

        #endregion

        #region IEnumerator Members

        object System.Collections.IEnumerator.Current
        {
            get { return _lst[enumposition]; }
        }

        public bool MoveNext()
        {
            if (enumposition < _lst.Count - 1)
            {
                enumposition++;
                return true;
            }
            else return false;
        }

        public void Reset()
        {
            enumposition = -1;
        }

        #endregion
    }
}
